<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        *:before, *:after {
            -webkit-box-sizing: border-box;
            -moz-box-sizing: border-box;
            box-sizing: border-box;
        }

        html,
        body,
        ul {
            height: 100%;
            font-family: Helvetica;
            margin: 0;
            padding: 0
        }

        li {
            border-bottom: 1px solid #E0E0E0;
            font-size: 20px;
            font-weight: bold;
            list-style: none outside none;
            margin: 0;
            padding: 8px 0 8px 10px;
            position: relative;
            -webkit-transition: opacity .75s ease-in;
            background: #fff;
        }

        #window {
            height: 100%;
            overflow: hidden;
        }

        #content {
            position: absolute;
            top: 0;
            background: linear-gradient( #2A65E3, #3875f8);
            width: 100%;
            top:0;
            transition: transform .3s linear;
        }

        #pull_to_refresh,
        #refreshing {
            line-height: 50px;
            text-align: center;
            background: #2A65E3;
            color:#ffffff;
        }

        .img {
            height: 70px;
            width: 70px;
            background: #cccccc;
        }

        .line-top,
        .line-mid,
        .line-bottom {
            height: 8px;
            width: 70%;
            margin-left: 92px;
            position: absolute;
            background-color: #cccccc;
        }

        .line-top {
            top: 22px;
            width: 100px;
        }

        .line-mid {
            bottom: 40px;
        }

        .line-bottom {
            width: 65%;
            bottom: 26px;
        }
    </style>
</head>
<body>
    <div id="window">
        <div id="pull_to_refresh">Pull and release to refresh</div>
        <div id="refreshing" style="display: none;">Refreshing</div>
        <div id="content">
            <ul id="list">
                <li class="item">
                    <div class="img"></div>
                    <span class="line-top"></span>
                    <span class="line-mid"></span>
                    <span class="line-bottom"></span>
                </li>
                <li class="item">
                    <div class="img"></div>
                    <span class="line-top"></span>
                    <span class="line-mid"></span>
                    <span class="line-bottom"></span>
                </li>
                <li class="item">
                    <div class="img"></div>
                    <span class="line-top"></span>
                    <span class="line-mid"></span>
                    <span class="line-bottom"></span>
                </li>
                <ul>
                </ul>
            </ul>
        </div>
    </div>
    <script>
        let $ = (selector,context) => {
            return new Init(selector,context);
        };

        function Init(selector,context) {
            this.initProps(selector,context);
        }

        Init.eventDep = {};

        $.isDOM = (el) =>{
            let elTypes = [Node.ELEMENT_NODE,Node.DOCUMENT_NODE];
            return elTypes.includes(el.nodeType);
        };

        $.each = (targets,callback) => {
            targets = Array.from(targets);
            let i = 0;
            let flag = true;
            while(i < (targets.length || 0)) {
                let el = targets[i];   
                typeof callback == 'function' && (flag = callback.call(el,el,i));
                if(flag === false){ break; }
                i++;
            }
            return targets;
        }

        $.query = (selector, oParent = document) => {
            let els = Array.from(selector);
            if($.isDOM(selector)){
                return [selector];
            }
            if(typeof selector == 'string'){
                return oParent.querySelectorAll(selector);
            }
            return els;
        };

        $.contains = (targetEl,els) => {
            let isContains = false;
            $.each(targetEl, target => {
                $.each(els, el => {
                    if(target.contains(el)){
                        isContains = true;
                        return false;
                    }
                });
                if(isContains){return false}
            })
            return isContains;
        }
        
        $.prototype = Object.create(Array.prototype);
        
        let c = null;

        Object.assign($.prototype,{
            constructor: $,
            initProps(selector, context) {
                let els = $.query(selector, context);
                Object.assign(this, els);
                this.length = els.length || 0;
                this.context = context || document; 
            },
            find(selector) {
                let doms = [];
                this.each(el => {
                    let els = $.query(selector,el);
                    doms.push(...els);
                });
                return $(doms);
            },
            each(callback) {
                return $.each(this, callback);
            },
            evtListener(eventName, handler) {
                return this.each(el => {
                    let callback = e => typeof handler == 'function' && handler.call(el,e);
                    let events = Init.eventDep[el] || (Init.eventDep[el] = {});
                    (events[eventName] || (events[eventName] = [])).push(callback);
                    el.addEventListener(eventName, callback, false);
                });
            },
            off(eventName) {
                return this.each(el => {
                    let deps = Init.eventDep[el];
                    let events = deps[eventName];
                    if(deps && events && events.length > 0){
                        $.each(events, handler => {
                            el.removeEventListener(eventName, handler, false);
                        })
                    }
                })
            },
            contains(nodes) {
                return $.contains(this,nodes);
            },
            on(eventName,selector,callback) {
                return this.evtListener(eventName, e => {
                    let $self = $(e.target);
                    let $target = this.find(selector);
                    if($target.contains($self)){
                        typeof callback == 'function' && callback.call($self[0],e);
                    }
                });
            }
        })

        Init.prototype = $.prototype;
    </script>
    <script>
        let drag = ($container) => {
            let $doc = $(document);
            let mouserStartY = 0; // 鼠标移动距离
            let dragResistance = 0.2; // 拖拽抗力，胡可定律k
            let y = 0; //下拉容器元素移动距离
            let maxDistance = 150; // 最大允许移动的距离
            let minDistance = 50; // 最小需要移动的距离
            $container.evtListener('mousedown', e => {
                e.preventDefault();
                mouserStartY = e.clientY;
                moveEvt();
            });
            let moveEvt = () => {
                $doc.evtListener('mousemove', e => {
                    if(e.clientY < mouserStartY){return}
                    y = Math.abs(mouserStartY - e.clientY) * dragResistance;
                    y > maxDistance && (y = maxDistance);
                    $container[0].style.top = y + 'px';
                    $container[0].style['-webkit-transition'] = ''
                })
                $doc.evtListener('mouseup', e => {
                    if(y > minDistance){
                        isRefresh = true;
                        console.log('刷新成功，事件')
                    }
                    $doc.off('mousemove');
                    $doc.off('mouseup');
                    $doc.off('transitionend');
                    $container[0].style.top = '0';
                    $container[0].style['-webkit-transition'] = '.3s'
                });
                $container.evtListener('transitionend', () => {
                    isRefresh = false;
                });
            };
        }

        let $c = $('#content');
        drag($c);
    </script>
</body>
</html>